function deepCopy(source) {
  let obj = source.constructor === Object ? {} : []
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      if (source[key] && typeof source[key] === 'object') {
        obj[key] = source[key].constructor === Object ? {} : [];
        obj[key] = deepCopy(source[key]);
      } else {
        obj[key] = source[key]

      }
    }
  }
  return obj;
}

let a = { name: NaN, age: null, sex: function () { }, job: undefined };
let b = deepCopy(a)
let c = JSON.parse(JSON.stringify(a))


let deepClone = source => {
  if (Object.prototype.toString.call(source) !== '[object Object]') {
    return source;
  }
  let obj = Array.isArray(source) ? [] : {};
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      if (source[key] && typeof source[key] === 'object') {
        obj[key] = Array.isArray(source[key]) ? [] : {};
        obj[key] = deepClone(source[key])
      } else {
        obj[key] = source[key];
      }
    }
  }
  return obj;
}

let deepCloneV2 = source => {
  if (Object.prototype.toString.call(source) !== '[object Object]') {
    return source;
  }

  const obj = {};
  const map = new Map();
  const stack = [
    {
      parent: obj,
      key: undefined,
      raw: source
    }
  ];

  while (stack.length) {
    const { parent, key, raw } = stack.pop();
    let child = parent;
    if (map.get(raw)) {
      child[key] = map.get(raw);
      continue;
    }
    if (key) {
      child = parent[key] = {};
    }
    map.set(raw, child);
    for (const key in raw) {
      if (raw.hasOwnProperty(key)) {
        if (Object.prototype.toString.call(raw[key]) === '[object Object]') {
          stack.push(
            {
              parent: child,
              key,
              raw: raw[key]
            }
          );
        } else {
          child[key] = raw[key];
        }
      }
    }
  }
  return obj;
}

let x = {
  some: 1
}

x.A = x;
let d = deepCloneV2(x)
console.log(d)